package dto

import (
	"errors"
	"fmt"
	"time"
	"yunj/app/model"
	"yunj/pkg/global"
	"yunj/pkg/yunj/app/enum/stateenum"
	yunjModel "yunj/pkg/yunj/app/model"
	"yunj/pkg/yunj/core/db"
	"yunj/pkg/yunj/util"

	"github.com/worklz/go-validate"
	"gorm.io/gorm"
)

type AdminCategoryPageHandleParam struct {
	validate.Validator
	Event          string          `json:"event"`
	Pid            uint64          `json:"pid"`      // event = Add 时，必须
	Id             uint64          `json:"id"`       // event = RecycleBin 时，必须
	TargetId       uint64          `json:"targetId"` // event = Drag 时，必须
	Mode           string          `json:"mode"`     // event = Drag 时，必须
	InsertCategory *model.Category // 要添加的分类
	Category       *model.Category // id映射的分类
	DragSortSql    string          // 拖拽排序的sql
}

func (v *AdminCategoryPageHandleParam) DefineRules() map[string]interface{} {
	return map[string]interface{}{
		"id":       "required|positiveInt",
		"pid":      "required|nonnegativeInt",
		"targetId": "required|positiveInt",
		"mode":     "required|in:prev,next,inner",
	}
}

func (v *AdminCategoryPageHandleParam) DefineScenes() map[string][]string {
	return map[string][]string{
		"Add":        {"pid"},
		"RecycleBin": {"id"},
		"Drag":       {"id", "targetId", "mode"},
	}
}

func (v *AdminCategoryPageHandleParam) HandleDatas(datas map[string]interface{}, scene string) (err error) {
	if scene == "Add" {
		err = v.HandleDatasByAdd()
		if err != nil {
			return
		}
	}
	if scene == "RecycleBin" {
		err = v.HandleDatasByRecycleBin()
		if err != nil {
			return
		}
	}
	if scene == "Drag" {
		err = v.HandleDatasByDrag()
		if err != nil {
			return
		}
	}
	return
}

func (v *AdminCategoryPageHandleParam) HandleDatasByAdd() (err error) {
	// pid
	pids := yunjModel.Uint64SliceJson{}
	level := 0
	if v.Pid != 0 {
		var parentCategory model.Category
		if dbErr := global.MySQL.Where("id = ? and state = ?", v.Pid, stateenum.NORMAL).First(&parentCategory).Error; dbErr != nil {
			if dbErr == gorm.ErrRecordNotFound {
				err = errors.New("父级分类不存在")
			} else {
				err = fmt.Errorf("父级分类匹配异常！%v", dbErr)
			}
			return
		}
		level = parentCategory.Level + 1
		if level > global.Config.Default.Category.LevelLimit {
			err = errors.New("父级分类层级不能超过3级")
			return
		}
		pids = append(parentCategory.Pids, v.Pid)
	}
	// sort
	var maxSort int
	global.MySQL.Model(&model.Category{}).Where("pid = ? and state <> ?", v.Pid, stateenum.DELETED).Select("max(sort)").Scan(&maxSort)
	currTime := time.Now().In(time.Local)
	insertCategory := model.Category{
		Pid:   v.Pid,
		Pids:  pids,
		Level: level,
		Name:  "新分类",
		Sort:  maxSort + 1,
	}
	alias, _ := util.ToString(currTime.Unix())
	insertCategory.Alias = alias
	insertCategory.CreateTime = currTime.Unix()
	insertCategory.LastUpdateTime = currTime.Unix()
	insertCategory.State = stateenum.NORMAL
	v.InsertCategory = &insertCategory
	return
}

func (v *AdminCategoryPageHandleParam) HandleDatasByRecycleBin() (err error) {
	// id
	var category model.Category
	if dbErr := global.MySQL.Where("id = ? and state = ?", v.Id, stateenum.NORMAL).First(&category).Error; dbErr != nil {
		if dbErr == gorm.ErrRecordNotFound {
			err = errors.New("分类不存在")
		} else {
			err = fmt.Errorf("分类匹配异常！%v", dbErr)
		}
		return
	}
	if category.Alias == global.Config.Default.Category.Alias {
		err = fmt.Errorf("分类【%s】为系统默认分类，不能删除！", category.Name)
		return
	}
	v.Category = &category
	return
}

func (v *AdminCategoryPageHandleParam) HandleDatasByDrag() (err error) {
	// id
	var category model.Category
	if dbErr := global.MySQL.Where("id = ? and state = ?", v.Id, stateenum.NORMAL).First(&category).Error; dbErr != nil {
		if dbErr == gorm.ErrRecordNotFound {
			err = errors.New("分类不存在")
		} else {
			err = fmt.Errorf("分类匹配异常！%v", dbErr)
		}
		return
	}
	// targetId
	var targetCategory model.Category
	if dbErr := global.MySQL.Where("id = ? and state = ?", v.TargetId, stateenum.NORMAL).First(&targetCategory).Error; dbErr != nil {
		if dbErr == gorm.ErrRecordNotFound {
			err = errors.New("移动目标分类不存在")
		} else {
			err = fmt.Errorf("移动目标分类匹配异常！%v", dbErr)
		}
		return
	}
	// mode
	currTime := time.Now().In(time.Local)
	// 移动到目标分类内部
	if v.Mode == "inner" {
		level := targetCategory.Level + 1
		if level > global.Config.Default.Category.LevelLimit {
			err = errors.New("移动目标分类层级不能超过3级")
			return
		}
		category.Pid = targetCategory.Id
		category.Pids = append(targetCategory.Pids, v.Pid)
		category.Level = level
		category.Sort = 0
		category.LastUpdateTime = currTime.Unix()
		v.Category = &category
		return
	}
	// 移动到目标分类前/后
	var targetLevelCateIds []uint64
	if dbErr := global.MySQL.Model(&model.Category{}).Where("id <> ? and pid = ? and state <> ?", v.Id, targetCategory.Pid, stateenum.DELETED).Order("sort asc").Pluck("id", &targetLevelCateIds).Error; dbErr != nil {
		err = fmt.Errorf("移动目标同级分类数据获取异常！%v", dbErr)
		return
	}
	category.Pid = targetCategory.Pid
	category.Pids = targetCategory.Pids
	category.Level = targetCategory.Level
	category.LastUpdateTime = currTime.Unix()
	sort := 0
	targetLevelCateSortCaseids := ""
	targetLevelCateSortCaseSql := ""
	for _, targetLevelCateId := range targetLevelCateIds {
		if targetLevelCateId == targetCategory.Id {
			if v.Mode == "prev" {
				category.Sort = sort
				sort += 1
			} else if v.Mode == "next" {
				category.Sort = sort + 1
			} else {
				err = errors.New("参数[mode]异常")
				return
			}
		}
		targetLevelCateSortCaseids += fmt.Sprintf(",%d", targetLevelCateId)
		targetLevelCateSortCaseSql += fmt.Sprintf(" WHEN %d THEN %d ", targetLevelCateId, sort)
		sort += 1
	}
	targetLevelCateSortCaseids = targetLevelCateSortCaseids[1:]
	v.DragSortSql = fmt.Sprintf("UPDATE %s SET sort = (CASE id %s END),last_update_time = %d WHERE id IN (%s)", db.Model(&model.Category{}).GetTableName(), targetLevelCateSortCaseSql, currTime.Unix(), targetLevelCateSortCaseids)
	v.Category = &category
	return
}
